package com.ibuildmap;

import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Toast;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.Marker;;
import com.baidu.mapapi.map.MyLocationConfiguration;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.map.TextureMapView;
import com.baidu.mapapi.model.LatLng;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.events.RCTEventEmitter;

/**
 * Created by youkai on 2017/5/23.
 */
public class IbuildMapNavManager extends ViewGroupManager<TextureMapView> implements SensorEventListener {

    ThemedReactContext mReactContext;
    BaiduMap mBaiduMap;
    TextureMapView mMapView;

    LocationClient mLocationClient;
    private SensorManager mSensorManager;
    private Double lastX = 0.0;
    private int mCurrentDirection = 0;
    private double mCurrentLat = 0.0;
    private double mCurrentLon = 0.0;
    private float mCurrentAccracy;
    private MyLocationData locData;

    @Override
    public String getName() {
        return "BDProjectNavMap";
    }

    @Override
    protected TextureMapView createViewInstance(ThemedReactContext reactContext) {
        mReactContext = reactContext;
        mMapView = new TextureMapView(reactContext);
        mMapView.showZoomControls(false);

        mBaiduMap = mMapView.getMap();
        mBaiduMap.setMyLocationEnabled(true);
        mBaiduMap.setMyLocationConfiguration(new MyLocationConfiguration(
                MyLocationConfiguration.LocationMode.NORMAL, true, null));
        mLocationClient = new LocationClient(reactContext.getApplicationContext());
        initLocation();
        mLocationClient.start();
        setListeners();
        return mMapView;
    }

    @ReactProp(name = "mapAnnotations")
    public void setMapAnnotations(TextureMapView view, @Nullable ReadableArray options) {
        view.getMap().clear();
        for (int i = 0; i < options.size(); i++) {
            CustomOverLayMgt customOverLayOptions = new CustomOverLayMgt(
                    view,
                    Util.getDataEntity(options.getMap(i))

            );
            customOverLayOptions.drawNav();
        }
        DataEntity dataEntity = Util.getDataEntity(options.getMap(0));
        MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(new LatLng(dataEntity.getLocationY(), dataEntity.getLocationX()));
        view.getMap().animateMapStatus(update);
    }

    @ReactProp(name = "mapUpdateStatus")
    public void setMapUpdateStatus(TextureMapView view, @Nullable ReadableMap mapUpdateStatus) {
        if(mapUpdateStatus.hasKey("state") && mapUpdateStatus.getString("state").equalsIgnoreCase("active")){
            view.onResume();
        }
        if (mapUpdateStatus.hasKey("zoomLevel")) {
            MapStatusUpdate update = MapStatusUpdateFactory.zoomTo((float) mapUpdateStatus.getDouble("zoomLevel"));
            view.getMap().animateMapStatus(update);
        }
    }

    @ReactProp(name = "toMyLocation")
    public void toMyLocation(TextureMapView view, @Nullable double isToMyLocation){
        if(isToMyLocation > 0){
            BDLocation myLocation = mLocationClient.getLastKnownLocation();
            toCenter(view,new LatLng(myLocation.getLatitude(),myLocation.getLongitude()),true);
        }
    }


    private void setListeners() {
        mBaiduMap.setOnMarkerClickListener(new BaiduMap.OnMarkerClickListener() {
            private WritableMap getMarkerParams(DataEntity dataEntity) {
                WritableMap writableMap = Arguments.createMap();
                writableMap.putInt("sysNo", dataEntity.getSysNo());
                writableMap.putInt("parentSysNo", dataEntity.getParentSysNo());
                writableMap.putString("areaCode", dataEntity.getAreaCode());
                writableMap.putString("areaName", dataEntity.getAreaName());
                writableMap.putInt("areaType", dataEntity.getAreaType());
                writableMap.putString("projectCode", dataEntity.getProjectCode());
                writableMap.putString("projectName", dataEntity.getProjectName());
                writableMap.putInt("projectLevel", dataEntity.getProjectLevel());
                writableMap.putInt("projectCount", dataEntity.getProjectCount());
                writableMap.putDouble("locationY", dataEntity.getLocationY());
                writableMap.putDouble("locationX", dataEntity.getLocationX());
                return writableMap;
            }

            @Override
            public boolean onMarkerClick(Marker marker) {
                Bundle extra = marker.getExtraInfo();
                if (extra == null) {
                    return false;
                }

                DataEntity dataEntity = (DataEntity) extra.getSerializable("entity");

                Intent i1 = new Intent();
                i1.setData(Uri.parse("baidumap://map/navi?location=" + dataEntity.getLocationY() + "," + dataEntity.getLocationX()));

                try {
                    mReactContext.startActivity(i1);
                } catch (ActivityNotFoundException ex) {
//                    Toast.makeText(mReactContext.getApplicationContext(),"未安装百度地图",Toast.LENGTH_SHORT).show();
                    sendEvent(mMapView,"onStartBaiduMapFailed",null);
                }
                return false;
            }
        });
        mLocationClient.registerLocationListener(new BDLocationListener() {
            @Override
            public void onReceiveLocation(BDLocation location) {
                if (location == null || mMapView == null) {
                    return;
                }
                mCurrentLat = location.getLatitude();
                mCurrentLon = location.getLongitude();
                mCurrentAccracy = location.getRadius();
                locData = new MyLocationData.Builder()
                        .accuracy(location.getRadius())
                        // 此处设置开发者获取到的方向信息，顺时针0-360
                        .direction(mCurrentDirection).latitude(location.getLatitude())
                        .longitude(location.getLongitude()).build();
                mBaiduMap.setMyLocationData(locData);
            }

            @Override
            public void onConnectHotSpotMessage(String s, int i) {

            }
        });
    }

    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        double x = sensorEvent.values[SensorManager.AXIS_X];
        if (Math.abs(x - lastX) > 1.0) {
            mCurrentDirection = (int) x;
            locData = new MyLocationData.Builder()
                    .accuracy(mCurrentAccracy)
                    // 此处设置开发者获取到的方向信息，顺时针0-360
                    .direction(mCurrentDirection).latitude(mCurrentLat)
                    .longitude(mCurrentLon).build();
            mBaiduMap.setMyLocationData(locData);
        }
        lastX = x;

    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    private void toCenter(TextureMapView mapView, LatLng latLng, boolean animate) {
        MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newLatLng(latLng);
        if (animate) {
            mapView.getMap().animateMapStatus(mMapStatusUpdate);
        } else {
            mapView.getMap().setMapStatus(mMapStatusUpdate);
        }
    }

    private void initLocation() {
        LocationClientOption option = new LocationClientOption();
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        //可选，默认高精度，设置定位模式，高精度，低功耗，仅设备

        option.setCoorType("bd09ll");
        //可选，默认gcj02，设置返回的定位结果坐标系

        int span = 1000;
        option.setScanSpan(span);
        //可选，默认0，即仅定位一次，设置发起定位请求的间隔需要大于等于1000ms才是有效的

        option.setIsNeedAddress(true);
        //可选，设置是否需要地址信息，默认不需要

        option.setOpenGps(true);
        //可选，默认false,设置是否使用gps

        option.setLocationNotify(true);
        //可选，默认false，设置是否当GPS有效时按照1S/1次频率输出GPS结果

        option.setIsNeedLocationDescribe(true);
        //可选，默认false，设置是否需要位置语义化结果，可以在BDLocation.getLocationDescribe里得到，结果类似于“在北京天安门附近”

        option.setIsNeedLocationPoiList(true);
        //可选，默认false，设置是否需要POI结果，可以在BDLocation.getPoiList里得到

        option.setIgnoreKillProcess(false);
        //可选，默认true，定位SDK内部是一个SERVICE，并放到了独立进程，设置是否在stop的时候杀死这个进程，默认不杀死

        option.SetIgnoreCacheException(false);
        //可选，默认false，设置是否收集CRASH信息，默认收集

        option.setEnableSimulateGps(false);
        //可选，默认false，设置是否需要过滤GPS仿真结果，默认需要

        mLocationClient.setLocOption(option);
    }

    /**
     * @param eventName
     * @param params
     */
    private void sendEvent(TextureMapView mapView, String eventName, @Nullable WritableMap params) {
        WritableMap event = Arguments.createMap();
        event.putMap("params", params);
        event.putString("type", eventName);
        mReactContext
                .getJSModule(RCTEventEmitter.class)
                .receiveEvent(mapView.getId(),
                        "topChange",
                        event);
    }
}